package com.bluedot.www.core.utils;

import com.bluedot.www.core.common.algorithm.DynamicCompiler;
import com.bluedot.www.core.common.algorithm.JavaSourceFileObject;
import com.sun.org.apache.xalan.internal.xsltc.compiler.CompilerException;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;

/**
 * 算法工具类
 * 1. 保存算法
 * 2. 检查算法是否有效（语法和接口是否符合规范）
 * 3. 根据全限定类名调用相应的算法
 *
 * @author He Peng
 * @version 1.0
 * @date 2021/9/3 14:16
 */
public class AlgorithmUtil {


    /**
     * 检查字符串中的代码是否存在错误
     *
     * @param fullName: 全限定类名，可以为空
     * @param content:  内容
     * @return boolean
     * @author He Peng
     * @date 2021/9/4 11:11
     */
    public static boolean checkAlgorithm(String fullName, String content) throws IOException, CompilerException {
        String path = AlgorithmUtil.class.getResource("/").getPath() + fullName;

        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null);
        JavaFileObject testFile = generateTest(fullName, content);
        Iterable<? extends JavaFileObject> classes = Collections.singletonList(testFile);
        File file = new File(path);
        Writer err = new FileWriter(file);

        JavaCompiler.CompilationTask task = javaCompiler.getTask(err, standardJavaFileManager, null, null, null, classes);

        if (task.call()) {
            return true;
        } else {
            FileReader fr = new FileReader(path);
            char[] buffer = new char[50];
            int len = 0;
            StringBuilder sb = new StringBuilder();
            while ((len = fr.read(buffer)) != -1) {
                sb.append(new String(buffer, 0, len));
            }
            fr.close();
            throw new CompilerException(sb.toString());
        }
    }

    // 已经保存的算法，直接通过类名进行实例化
    // 对于为保存的算法，首先保存，然后像数据库中插入信息
    public static Object runAlgorithm(String fullName, String content, Object[] params) {
        if (isPresent(fullName)) {
            System.out.println("存在");
        }

        DynamicCompiler dynamicCompiler = new DynamicCompiler();
        Class aClass = null;
        try {
            aClass = dynamicCompiler.compileAndLoad("com.bluedot.www.baiyetest.servlet.baiyetest.AlgorithmSwitch", content);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(aClass);
        Method[] declaredMethods = aClass.getDeclaredMethods();
        Method m = declaredMethods[0];
        try {
            m.invoke(aClass.getDeclaredConstructor().newInstance(), params);
        } catch (IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 保存代码至项目中的指定位置
     *
     * @param location: 项目的类路径 + 包路径
     * @param content:  Java代码字符串
     * @return boolean
     * @author He Peng
     * @date 2021/9/4 11:13
     */
    public static boolean saveAlgorithm(String location, String content) throws IOException {
        // 将算法保存到项目的指定路径
        File file = new File(location);
        PrintWriter pw = new PrintWriter(new FileWriter(file));
        pw.println(content);
        pw.close();
        // 动态编译
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int compilationResult = compiler.run(null, null, System.err, location);

        if (compilationResult == 0) {
//            boolean delete = file.delete();
            return true;
        } else {
            return false;
        }
    }

    // 判断一个类是否存在
    public static boolean isPresent(String fullName) {
        try {
            Class.forName(fullName);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * 根据字符串中的代码获取相应的Class对象
     *
     * @param fullName: 全限定类名
     * @param content:  字符串包含代码
     * @return java.lang.Class<?>
     * @author He Peng
     * @date 2021/9/7 9:56
     */
    public static Class<?> getAlgorithmClass(String fullName, String content) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        DynamicCompiler dynamicCompiler = new DynamicCompiler();
        Class<?> aClass = dynamicCompiler.compileAndLoad(fullName, content);
        return aClass;
    }


    //通过字符串创建一个待编译对象
    private static JavaFileObject generateTest(String className, String content) {
        JavaSourceFileObject so = null;
        so = new JavaSourceFileObject(className, content);
        return so;
    }


    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        String content = "package com.bluedot.www.baiyetest.servlet.baiyetest;" +
                "class Test {\n" +
                "  public static void main(String[] args) {\n" +
                "    System.out.println(\"success\");\n" +
                "  }\n" +
                "}\n";
        String fullName = "com.bluedot.www.baiyetest.servlet.baiyetest.Test";
        try {
            boolean b = checkAlgorithm("com.bluedot.www.baiyetest.servlet.baiyetest.Test", content);
            System.out.println(b);
        } catch (CompilerException e) {
            e.printStackTrace();
        }
        // 保存算法至项目
//        saveAlgorithm(AlgorithmUtil.class.getResource("/").getPath() + "com/bluedot/www/Test.java", content);
//        runAlgorithm("com.bluedot.www.Test", content, null);
        System.out.println(getAlgorithmClass(fullName, content));
    }

}
